package top.techqi.app.mcs51.usbdlk

import android.hardware.usb.UsbDevice
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.view.MenuProvider
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import top.techqi.app.mcs51.R
import top.techqi.app.mcs51.databinding.FragmentUsbdlkUartBinding
import top.techqi.app.mcs51.usbdlk.tile.UsbdlkUartRecvPortion
import top.techqi.app.mcs51.usbdlk.tile.UsbdlkUartSendPortion
import top.techqi.app.mcs51.usbdlk.vm.UsbdlkUartViewModel
import top.techqi.app.mcs51.usbdlk.vm.UsbdlkViewModel
import top.techqi.core.base.BaseFragment
import top.techqi.view.recyclerview.tile.TileAdapter

class UsbdlkUartFragment : BaseFragment<FragmentUsbdlkUartBinding>(
    FragmentUsbdlkUartBinding::inflate
), MenuProvider {
    private val device by lazy { requireArguments().getParcelable<UsbDevice>(EXTRA_DEVICE) }
    private val intfId by lazy { requireArguments().getInt(EXTRA_INTFID) }

    private val vmUsbdlk by viewModels<UsbdlkViewModel>(ownerProducer = { requireParentFragment() })
    private val vmUsbdlkUart by viewModels<UsbdlkUartViewModel>()

    private val tileAdapter = TileAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        tileAdapter.register(UsbdlkUartRecvPortion())
        tileAdapter.register(UsbdlkUartSendPortion())

        vmUsbdlkUart.openDevice(device!!, intfId)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        requireActivity().addMenuProvider(
            this, viewLifecycleOwner, Lifecycle.State.RESUMED
        )
        binding.rccUsbdlkUart.adapter = tileAdapter

        binding.btnUsbdlkUartSend.setOnClickListener {
            val text = binding.edtUsbdlkUartSend.text.toString()
            if (text.isNotEmpty()) {
                vmUsbdlkUart.send(text.toByteArray(charset = Charsets.US_ASCII))
            }
        }

        vmUsbdlkUart.streamData.observe(viewLifecycleOwner) { map ->
            val list = map.map { (k, v) ->
                val (time, type) = k
                val (_, hex, asc) = v
                if (type) {
                    UsbdlkUartSendPortion.Record(time, hex, asc)
                } else {
                    UsbdlkUartRecvPortion.Record(time, hex, asc)
                }
            }
            tileAdapter.commit(list)
        }
    }

    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
        menuInflater.inflate(R.menu.menu_usbdlk_uart, menu)
    }

    override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
        when (menuItem.itemId) {
            R.id.nav_action_usbdlk_uart_close -> {
                val device = device
                if (device != null) {
                    vmUsbdlk.closeDevice(device, intfId)
                }
                return true
            }
        }
        return false
    }

    companion object {
        private const val EXTRA_DEVICE = "device"
        private const val EXTRA_INTFID = "intfid"

        fun newInstance(device: UsbDevice, intfId: Int): UsbdlkUartFragment {
            return UsbdlkUartFragment().apply {
                arguments = bundleOf(
                    EXTRA_DEVICE to device,
                    EXTRA_INTFID to intfId
                )
            }
        }
    }
}
